#include "stdafx.h"
#include "2DRender.h"


C2DRender::C2DRender()
: m_width(1.0f)
, m_height(1.0f)
{
	m_vertices.reserve(1024);
	ResizeBuffers(m_vertices.capacity());
}

void C2DRender::Set2DMode(float width, float height)
{
	assert(m_width > 0);
	assert(m_height > 0);

	m_width = width;
	m_height = height;
}

void C2DRender::DrawQuad(float x, float y, float width, float height, const Color& color)
{
	float left = x;
	float top = y;
	float right = x + width;
	float bottom = y + height;

	if (IsInsideScreen(left, bottom) || IsInsideScreen(left, top) || IsInsideScreen(right, top) || IsInsideScreen(right, bottom))
	{
		AddVertex(left, bottom, color);
		AddVertex(left, top, color);
		AddVertex(right, top, color);

		AddVertex(left, bottom, color);
		AddVertex(right, top, color);
		AddVertex(right, bottom, color);
	}
}

void C2DRender::Flush()
{
	PROFILE_FUNCTION();

	uint vertex_count = m_vertices.size();
	if (vertex_count > 0)
	{
		//	check vertex & index buffers has enough size
		ResizeBuffers(m_vertices.capacity());

		IVertexBuffer* vb = m_pVertexBuffer.get();
		IIndexBuffer* ib = m_pIndexBuffer.get();

		//	fill vertex buffer
		uint bytes_to_copy = vertex_count * sizeof(S2DVertex);
		void* buffer = vb->Lock(0, 0, eVBLock_Discard);
		memcpy_s(buffer, bytes_to_copy, &m_vertices[0], bytes_to_copy);
		vb->Unlock();

		//	render
		gEnv->pRender->SetShader("2D");
		gEnv->pRender->DrawPrimitives(ePrimType_TriangleList, vb, vertex_count, ib, vertex_count);
		gEnv->pRender->SetShader(0);

		m_vertices.clear();
	}
}

bool C2DRender::IsInsideScreen(float x, float y) const
{
	return x >= 0 && x <= m_width && y >= 0 && y <= m_height;
}

void C2DRender::AddVertex(float x, float y, Color color)
{
	//	convert to clip space
	x = (2*x/m_width) - 1;
	y  = 1 - (2*y/m_height);

	//	fill vertex data
	S2DVertex v;
	v.pos.x = x;
	v.pos.y = y;
	v.uv.x = v.uv.y = 0;
	v.color = color;

	m_vertices.push_back(v);
}

void C2DRender::ResizeBuffers(uint vertex_count)
{
	//	vertex buffer
	uint vb_size = vertex_count * sizeof(S2DVertex);
	if (!m_pIndexBuffer.get() || vb_size > m_pVertexBuffer->GetSize())
	{
		IVertexBuffer* pVB = g_pRenderAPI->CreateVertexBuffer(vb_size, true);
		m_pVertexBuffer.reset(pVB);
	}

	//	index buffer
	uint ib_size = vertex_count * sizeof(uint16);
	if (!m_pIndexBuffer.get() || ib_size > m_pIndexBuffer->GetSize())
	{
		IIndexBuffer* pIB = g_pRenderAPI->CreateIndexBuffer(ib_size, false);
		m_pIndexBuffer.reset(pIB);

		//	setup indices
		void* buffer = m_pIndexBuffer->Lock(0, 0, eIBLock_Discard);
		uint16* ib = static_cast<uint16*>(buffer);
		for (uint i = 0; i < vertex_count; ++i)
		{
			uint16& index = ib[i];
			index = i;
		}
		m_pIndexBuffer->Unlock();
	}
}